﻿using System.Collections.Generic;
using System.Windows.Media;

namespace System.Windows
{
    public static class DependencyObjectExtensions
    {
        public static T GetElement<T>(this FrameworkElement element) where T : DependencyObject
        {
            var @do = element as DependencyObject;
            var @rv = @do.GetParent<T>();

            return (T)rv;
        }

        public static FrameworkElement GetRootParent(this DependencyObject obj)
        {
            var parent = obj as DependencyObject;
            var previous = null as DependencyObject;

            while (parent != null)
            {
                previous = parent;
                parent = VisualTreeHelper.GetParent(previous);
                //if (parent != null) Debug.WriteLine("{0}", parent.GetType().ToString());
            }

            return (FrameworkElement)previous;
        }

        public static T GetParent<T>(this DependencyObject obj) where T : DependencyObject
        {
            var parent = null as DependencyObject;

            parent = VisualTreeHelper.GetParent(obj);

            while (parent != null)
            {
                if (parent != null && parent is T)
                {
                    break;
                }

                if (parent != null)
                {
                    parent = GetParent<T>(parent);

                    if (parent != null && parent.GetType() == typeof(T))
                    {
                        break;
                    }
                }
            }

            return parent as T;
        }

        public static object GetParentByName(this DependencyObject obj, string name)
        {
            var parent = null as DependencyObject;

            parent = VisualTreeHelper.GetParent(obj);

            while (parent != null)
            {
                if (parent != null && ((FrameworkElement)parent).Name == name)
                {
                    break;
                }

                if (parent != null)
                {
                    parent = (DependencyObject)GetParentByName(parent, name);

                    if (parent != null && ((FrameworkElement)parent).Name == name)
                    {
                        break;
                    }
                }
            }
            return parent;
        }

        public static object GetParent(this DependencyObject obj, string type)
        {
            var parent = null as DependencyObject;

            parent = VisualTreeHelper.GetParent(obj);

            while (parent != null)
            {
                if (parent != null && parent.GetType().ToString() == type)
                {
                    break;
                }

                if (parent != null)
                {
                    parent = (DependencyObject)GetParent(parent, type);

                    if (parent != null && parent.GetType().ToString() == type)
                    {
                        break;
                    }
                }
            }
            return parent;
        }

        public static T GetChild<T>(this DependencyObject obj) where T : DependencyObject
        {
            var child = null as DependencyObject;
            var found = false;
            var count = VisualTreeHelper.GetChildrenCount(obj);

            for (int i = 0; i < count; i++)
            {
                child = VisualTreeHelper.GetChild(obj, i);

                while (child != null)
                {
                    if (child != null && child is T)
                    {
                        found = true;
                        break;
                    }

                    if (child != null)
                    {
                        child = GetChild<T>(child);

                        if (child != null && child is T)
                        {
                            found = true;
                            break;
                        }
                    }
                }

                if (found) break;
            }

            return child as T;
        }

        public static void GetChildren<T>(this DependencyObject obj, List<T> list) where T : DependencyObject
        {
            var child = null as DependencyObject;
            var count = VisualTreeHelper.GetChildrenCount(obj);

            for (int i = 0; i < count; i++)
            {
                child = VisualTreeHelper.GetChild(obj, i);

                while (child != null)
                {
                    if (child != null && child is T)
                    {
                        list.Add((T)child);
                        break;
                    }
                    else if (child != null)
                    {
                        GetChildren<T>(child, list);
                        break;
                    }
                }
            }
        }

        public static FrameworkElement GetChildByName(this DependencyObject parent, string name)
        {
            if (null == parent)
            {
                return null;
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                return null;
            }

            var count = VisualTreeHelper.GetChildrenCount(parent);
            var child = null as DependencyObject;
            var childFE = null as FrameworkElement;

            for (int i = 0; i < count; i++)
            {
                child = VisualTreeHelper.GetChild(parent, i);
                childFE = child as FrameworkElement;

                if (null != childFE)
                {
                    if (childFE.Name == name)
                    {
                        return childFE;
                    }
                }
            }

            return null;
        }
    }
}
